﻿using OpenCvSharp;

using System;
using System.Threading.Tasks;
using System.Windows.Media.Imaging;

using Xc.DataAccess.CodeReader.Models;
using Xc.DataAccess.CodeReader.Models.Filters;
using Xc.DataAccess.CodeReader.Properties;
using Xc.DataAccess.Core;
using System.Linq;
using System.Collections.Generic;

namespace Xc.DataAccess.CodeReader
{
    /// <summary>
    /// 相机服务
    /// </summary>
    public class OpenCvService : IOpenCvService
    {
        private readonly IMatFilterService matFilterService;
        Mat mat = new Mat();
        private VideoCapture videoCapture;

        public OpenCvService(IMatFilterService matFilterService)
        {
            this.matFilterService = matFilterService;
        }
        /// <summary>
        /// 过滤器清单信息
        /// </summary>
        private static readonly List<FilterDetailInfo> filterDetailInfos = new List<FilterDetailInfo>();
        /// <summary>
        /// 获取过滤器列表
        /// </summary>
        public FilterDetailInfo[] FilterInfos
        { 
            get
            {
                if (filterDetailInfos.Count==0)
                {
                    var type = typeof(FilterBase);
                    var c = typeof(OpenCvService).Assembly.GetTypes().Where(p => type.IsAssignableFrom(p) && p.IsAbstract == false);
                    foreach (var item in c)
                    {
                        var filter=  (FilterAttribute)Attribute.GetCustomAttribute(item, typeof(FilterAttribute));
                        if (filter==null)
                        {
                            throw new AttributeEmptyException(TextResource.you_must_set_filter_attribute);
                        }
                        if (filter.FilterType==FilterType.Algorithm)
                        {
                            if (!item.Name.StartsWith("Algorithm"))
                            {
                                throw new AttributeEmptyException(TextResource.algorithm_must_start_with_Algorithm);
                            }
                        }
                        else if (filter.FilterType == FilterType.Draw)
                        {
                            if (!item.Name.StartsWith("Draw"))
                            {
                                throw new AttributeEmptyException(TextResource.draw_must_start_with_draw);
                            }
                        }
                        FilterDetailInfo filterDetailInfo = new FilterDetailInfo()
                        {
                            FilterType = item,
                            ProcessName = filter.ProcessName,
                            TypeName = item.Name
                        };
                        var properties = item.GetProperties();
                        foreach (var property in properties)
                        {
                            var ignore = (IgnoreParameterAttribute)Attribute.GetCustomAttribute(property, typeof(IgnoreParameterAttribute));
                            if (ignore != null)
                            {
                                continue;
                            }
                            var attr = (OutputParameterAttribute)Attribute.GetCustomAttribute(property, typeof(OutputParameterAttribute));
                            if (attr != null)
                            {
                                filterDetailInfo.OutputParameters.Add(new OutputParameterInfo { DefaultValueEvent =()=> property.GetValue((FilterBase)Activator.CreateInstance(item)), Name = attr.Name, TypeName = property.GetType().Name, PropertyName = property.Name, Type = property.GetType() });
                            }
                            else
                            {
                                var input = (InputParameterAttribute)Attribute.GetCustomAttribute(property, typeof(InputParameterAttribute));
                                if (input != null)
                                {
                                    filterDetailInfo.InputParameters.Add(new InputParameterInfo { DefaultValueEvent =()=> property.GetValue((FilterBase)Activator.CreateInstance(item)), Name = input.Name, TypeName = property.GetType().Name, PropertyName = property.Name, Type = property.GetType(), IsMust = input.ParameterType });
                                }
                                else
                                {
                                    throw new ArgumentException($"过滤器:{item.Name}参数:{property.Name}无效，必须指定输入输出特性");
                                }
                            }
                        }
                        filterDetailInfos.Add(filterDetailInfo);
                    }
                }

                return filterDetailInfos.OrderBy(p => p.TypeName).ToArray();
            }
        }

        /// <summary>
        /// 关闭服务
        /// </summary>
        /// <returns></returns>
        public Result Close()
        {
            if (videoCapture != null)
            {
                videoCapture.Release();
            }
            return Result.Accept(Properties.TextResource.close_camera_sussessful);
        }
        /// <summary>
        /// 开启服务
        /// </summary>
        /// <param name="option"></param>
        /// <returns></returns>
        public async Task<Result> OpenAsync(CameraServiceOption option)
        {
         return  await Task.Run(() => {
                videoCapture = OpenCvSharp.VideoCapture.FromCamera(option.ServiceIndex);
                if (videoCapture == null)
                {
                    return Result.Reject(Properties.TextResource.not_found_suitable_camera);
                }
                else
                {
                    return Result.Accept(Properties.TextResource.open_camera_successful);
                }
            });

        }
        /// <summary>
        /// 读取一张图片
        /// </summary>
        /// <returns></returns>
        public ResultData<BitmapImage> ToImage(Mat mat)
        {
            try
            {
                BitmapImage bitmapImage = new BitmapImage();
                bitmapImage.BeginInit();
                var stream = new System.IO.MemoryStream();
                mat.ToMemoryStream().CopyTo(stream);
                bitmapImage.StreamSource = stream;
                bitmapImage.EndInit();
                return ResultData<BitmapImage>.Accept(TextResource.get_mat_successful, bitmapImage);

            }
            catch (Exception err)
            {
               return ResultData<BitmapImage>.Reject(err.Message,null);
            }
        }
        /// <summary>
        /// 获取一张图片
        /// </summary>
        /// <returns></returns>
        public async Task<ResultData<Mat>> ReadMat(params FilterBase[] imageFilter)
        {
           return await Task.Run(async () =>
           {
               if (videoCapture==null)
               {
                   return ResultData<Mat>.Reject("请先打开相机",null);
               }
                var img = videoCapture.Read(mat);
                if (img)
                {
                    var matResult =await matFilterService.UseDirect(mat, imageFilter);
                    if (matResult.IsSuccess)
                    {
                        return ResultData<Mat>.Accept(TextResource.get_mat_successful, matResult.Data);

                    }
                    else
                    {
                        return ResultData<Mat>.Reject(matResult.Message, matResult.Data);

                    }
                }
                else
                {
                    return ResultData<Mat>.Reject(TextResource.get_mat_failed, null);
                }
            });
            
        }
    }
}
